﻿using Microsoft.Extensions.Logging;
using System;
using System.Buffers;
using System.IO;
using System.IO.Pipelines;
using System.Net;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace JTActiveSafety.Gateway.Internal
{
    /// <summary>
    /// 请求处理器
    /// </summary>
    internal interface IRequestProcessor
    {
        Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> application);
        void StopProcessingNextRequest();//停止处理下一个请求 
        void HandleRequestHeadersTimeout(); //处理请求头超时
        void HandleReadDataRateTimeout(); //读取数据速率
        void OnInputOrOutputCompleted();
        void Tick(DateTimeOffset now);
        void Abort(ConnectionAbortedException ex);
    }
    internal interface IHttpOutputAborter
    {
        void Abort(ConnectionAbortedException abortReason);
        void OnInputOrOutputCompleted();
    }
    internal interface IHttpResponseControl
    {
        void ProduceContinue();
        Memory<byte> GetMemory(int sizeHint = 0);
        Span<byte> GetSpan(int sizeHint = 0);
        void Advance(int bytes);
        ValueTask<FlushResult> FlushPipeAsync(CancellationToken cancellationToken);
        ValueTask<FlushResult> WritePipeAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken);
        void CancelPendingFlush();
        Task CompleteAsync(Exception exception = null);
    }
    internal enum RequestProcessingStatus
    {
        RequestPending,
        ParsingRequestLine,
        ParsingHeaders,
        AppStarted,
        HeadersCommitted,
        HeadersFlushed,
        ResponseCompleted
    }

    //    internal abstract partial class HttpProtocol //: IHttpResponseControl
    //    {
    //        private static readonly byte[] _bytesConnectionClose = Encoding.ASCII.GetBytes("\r\nConnection: close");
    //        private static readonly byte[] _bytesConnectionKeepAlive = Encoding.ASCII.GetBytes("\r\nConnection: keep-alive");
    //        private static readonly byte[] _bytesTransferEncodingChunked = Encoding.ASCII.GetBytes("\r\nTransfer-Encoding: chunked");
    //        private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: " + Constants.ServerName);
    //        internal const string SchemeHttp = "http";
    //        internal const string SchemeHttps = "https";

    //        protected BodyControl _bodyControl;
    //        private Stack<KeyValuePair<Func<object, Task>, object>> _onStarting;
    //        private Stack<KeyValuePair<Func<object, Task>, object>> _onCompleted;

    //        private readonly object _abortLock = new object();
    //        protected volatile bool _connectionAborted;
    //        private bool _preventRequestAbortedCancellation;
    //        private CancellationTokenSource _abortedCts;
    //        private CancellationToken? _manuallySetRequestAbortToken;

    //        protected RequestProcessingStatus _requestProcessingStatus;

    //        // Keep-alive is default for HTTP/1.1 and HTTP/2; parsing and errors will change its value
    //        // volatile, see: https://msdn.microsoft.com/en-us/library/x13ttww7.aspx
    //        protected volatile bool _keepAlive = true;
    //        // _canWriteResponseBody is set in CreateResponseHeaders.
    //        // If we are writing with GetMemory/Advance before calling StartAsync, assume we can write and throw away contents if we can't.
    //        private bool _canWriteResponseBody = true;
    //        private bool _hasAdvanced;
    //        private bool _isLeasedMemoryInvalid = true;
    //        private bool _autoChunk;
    //        protected Exception _applicationException;
    //        private BadHttpRequestException _requestRejectedException;

    //        protected HttpVersion _httpVersion;
    //        // This should only be used by the application, not the server. This is settable on HttpRequest but we don't want that to affect
    //        // how Kestrel processes requests/responses.
    //        private string _httpProtocol;

    //        private string _requestId;
    //        private int _requestHeadersParsed;

    //        private long _responseBytesWritten;

    //        private HttpConnectionContext _context;
    //        private RouteValueDictionary _routeValues;
    //        private Endpoint _endpoint;

    //        protected string _methodText = null;
    //        private string _scheme = null;
    //        private Stream _requestStreamInternal;
    //        private Stream _responseStreamInternal;

    //        public void Initialize(HttpConnectionContext context)
    //        {
    //            _context = context;

    //            ServerOptions = ServiceContext.ServerOptions;

    //            Reset();

    //            HttpResponseControl = this;
    //        }

    //        public IHttpResponseControl HttpResponseControl { get; set; }

    //        public ServiceContext ServiceContext => _context.ServiceContext;
    //        private IPEndPoint LocalEndPoint => _context.LocalEndPoint;
    //        private IPEndPoint RemoteEndPoint => _context.RemoteEndPoint;
    //        public ITimeoutControl TimeoutControl => _context.TimeoutControl;

    //        public IFeatureCollection ConnectionFeatures => _context.ConnectionFeatures;
    //        public IHttpOutputProducer Output { get; protected set; }

    //        protected IKestrelTrace Log => ServiceContext.Log;
    //        private DateHeaderValueManager DateHeaderValueManager => ServiceContext.DateHeaderValueManager;
    //        // Hold direct reference to ServerOptions since this is used very often in the request processing path
    //        protected KestrelServerOptions ServerOptions { get; set; }
    //        protected string ConnectionId => _context.ConnectionId;

    //        public string ConnectionIdFeature { get; set; }
    //        public bool HasStartedConsumingRequestBody { get; set; }
    //        public long? MaxRequestBodySize { get; set; }
    //        public MinDataRate MinRequestBodyDataRate { get; set; }
    //        public bool AllowSynchronousIO { get; set; }

    //        /// <summary>
    //        /// The request id. <seealso cref="HttpContext.TraceIdentifier"/>
    //        /// </summary>
    //        public string TraceIdentifier
    //        {
    //            set => _requestId = value;
    //            get
    //            {
    //                // don't generate an ID until it is requested
    //                if (_requestId == null)
    //                {
    //                    _requestId = CreateRequestId();
    //                }
    //                return _requestId;
    //            }
    //        }

    //        public bool IsUpgradableRequest { get; private set; }
    //        public bool IsUpgraded { get; set; }
    //        public IPAddress RemoteIpAddress { get; set; }
    //        public int RemotePort { get; set; }
    //        public IPAddress LocalIpAddress { get; set; }
    //        public int LocalPort { get; set; }
    //        public string Scheme { get; set; }
    //        public HttpMethod Method { get; set; }
    //        public string MethodText => ((IHttpRequestFeature)this).Method;
    //        public string PathBase { get; set; }

    //        public string Path { get; set; }
    //        public string QueryString { get; set; }
    //        public string RawTarget { get; set; }

    //        public string HttpVersion
    //        {
    //            get
    //            {
    //                if (_httpVersion == Http.HttpVersion.Http3)
    //                {
    //                    return AspNetCore.Http.HttpProtocol.Http3;
    //                }
    //                if (_httpVersion == Http.HttpVersion.Http2)
    //                {
    //                    return AspNetCore.Http.HttpProtocol.Http2;
    //                }
    //                if (_httpVersion == Http.HttpVersion.Http11)
    //                {
    //                    return AspNetCore.Http.HttpProtocol.Http11;
    //                }
    //                if (_httpVersion == Http.HttpVersion.Http10)
    //                {
    //                    return AspNetCore.Http.HttpProtocol.Http10;
    //                }

    //                return string.Empty;
    //            }

    //            [MethodImpl(MethodImplOptions.AggressiveInlining)]
    //            set
    //            {
    //                // GetKnownVersion returns versions which ReferenceEquals interned string
    //                // As most common path, check for this only in fast-path and inline
    //                if (ReferenceEquals(value, AspNetCore.Http.HttpProtocol.Http3))
    //                {
    //                    _httpVersion = Http.HttpVersion.Http3;
    //                }
    //                else if (ReferenceEquals(value, AspNetCore.Http.HttpProtocol.Http2))
    //                {
    //                    _httpVersion = Http.HttpVersion.Http2;
    //                }
    //                else if (ReferenceEquals(value, AspNetCore.Http.HttpProtocol.Http11))
    //                {
    //                    _httpVersion = Http.HttpVersion.Http11;
    //                }
    //                else if (ReferenceEquals(value, AspNetCore.Http.HttpProtocol.Http10))
    //                {
    //                    _httpVersion = Http.HttpVersion.Http10;
    //                }
    //                else
    //                {
    //                    HttpVersionSetSlow(value);
    //                }
    //            }
    //        }

    //        [MethodImpl(MethodImplOptions.NoInlining)]
    //        private void HttpVersionSetSlow(string value)
    //        {
    //            if (AspNetCore.Http.HttpProtocol.IsHttp3(value))
    //            {
    //                _httpVersion = Http.HttpVersion.Http3;
    //            }
    //            else if (AspNetCore.Http.HttpProtocol.IsHttp2(value))
    //            {
    //                _httpVersion = Http.HttpVersion.Http2;
    //            }
    //            else if (AspNetCore.Http.HttpProtocol.IsHttp11(value))
    //            {
    //                _httpVersion = Http.HttpVersion.Http11;
    //            }
    //            else if (AspNetCore.Http.HttpProtocol.IsHttp10(value))
    //            {
    //                _httpVersion = Http.HttpVersion.Http10;
    //            }
    //            else
    //            {
    //                _httpVersion = Http.HttpVersion.Unknown;
    //            }
    //        }

    //        public IHeaderDictionary RequestHeaders { get; set; }
    //        public IHeaderDictionary RequestTrailers { get; } = new HeaderDictionary();
    //        public bool RequestTrailersAvailable { get; set; }
    //        public Stream RequestBody { get; set; }
    //        public PipeReader RequestBodyPipeReader { get; set; }
    //        public HttpResponseTrailers ResponseTrailers { get; set; }

    //        private int _statusCode;
    //        public int StatusCode
    //        {
    //            get => _statusCode;
    //            set
    //            {
    //                if (HasResponseStarted)
    //                {
    //                    ThrowResponseAlreadyStartedException(nameof(StatusCode));
    //                }

    //                _statusCode = value;
    //            }
    //        }

    //        private string _reasonPhrase;

    //        public string ReasonPhrase
    //        {
    //            get => _reasonPhrase;

    //            set
    //            {
    //                if (HasResponseStarted)
    //                {
    //                    ThrowResponseAlreadyStartedException(nameof(ReasonPhrase));
    //                }

    //                _reasonPhrase = value;
    //            }
    //        }

    //        public IHeaderDictionary ResponseHeaders { get; set; }
    //        public Stream ResponseBody { get; set; }
    //        public PipeWriter ResponseBodyPipeWriter { get; set; }

    //        public CancellationToken RequestAborted
    //        {
    //            get
    //            {
    //                // If a request abort token was previously explicitly set, return it.
    //                if (_manuallySetRequestAbortToken.HasValue)
    //                {
    //                    return _manuallySetRequestAbortToken.Value;
    //                }

    //                lock (_abortLock)
    //                {
    //                    if (_preventRequestAbortedCancellation)
    //                    {
    //                        return new CancellationToken(false);
    //                    }

    //                    if (_connectionAborted)
    //                    {
    //                        return new CancellationToken(true);
    //                    }

    //                    if (_abortedCts == null)
    //                    {
    //                        _abortedCts = new CancellationTokenSource();
    //                    }

    //                    return _abortedCts.Token;
    //                }
    //            }
    //            set
    //            {
    //                // Set an abort token, overriding one we create internally.  This setter and associated
    //                // field exist purely to support IHttpRequestLifetimeFeature.set_RequestAborted.
    //                _manuallySetRequestAbortToken = value;
    //            }
    //        }

    //        public bool HasResponseStarted => _requestProcessingStatus >= RequestProcessingStatus.HeadersCommitted;

    //        public bool HasFlushedHeaders => _requestProcessingStatus >= RequestProcessingStatus.HeadersFlushed;

    //        public bool HasResponseCompleted => _requestProcessingStatus == RequestProcessingStatus.ResponseCompleted;

    //        protected HttpRequestHeaders HttpRequestHeaders { get; set; } = new HttpRequestHeaders();

    //        protected HttpResponseHeaders HttpResponseHeaders { get; } = new HttpResponseHeaders();

    //        public void InitializeBodyControl(MessageBody messageBody)
    //        {
    //            if (_bodyControl == null)
    //            {
    //                _bodyControl = new BodyControl(bodyControl: this, this);
    //            }

    //            (RequestBody, ResponseBody, RequestBodyPipeReader, ResponseBodyPipeWriter) = _bodyControl.Start(messageBody);
    //            _requestStreamInternal = RequestBody;
    //            _responseStreamInternal = ResponseBody;
    //        }

    //        // For testing
    //        internal void ResetState()
    //        {
    //            _requestProcessingStatus = RequestProcessingStatus.RequestPending;
    //        }

    //        public void Reset()
    //        {
    //            _onStarting?.Clear();
    //            _onCompleted?.Clear();
    //            _routeValues?.Clear();

    //            _requestProcessingStatus = RequestProcessingStatus.RequestPending;
    //            _autoChunk = false;
    //            _applicationException = null;
    //            _requestRejectedException = null;

    //            ResetFeatureCollection();

    //            HasStartedConsumingRequestBody = false;
    //            MaxRequestBodySize = ServerOptions.Limits.MaxRequestBodySize;
    //            MinRequestBodyDataRate = ServerOptions.Limits.MinRequestBodyDataRate;
    //            AllowSynchronousIO = ServerOptions.AllowSynchronousIO;
    //            TraceIdentifier = null;
    //            Method = HttpMethod.None;
    //            _methodText = null;
    //            _endpoint = null;
    //            PathBase = null;
    //            Path = null;
    //            RawTarget = null;
    //            QueryString = null;
    //            _httpVersion = Http.HttpVersion.Unknown;
    //            _httpProtocol = null;
    //            _statusCode = StatusCodes.Status200OK;
    //            _reasonPhrase = null;

    //            var remoteEndPoint = RemoteEndPoint;
    //            RemoteIpAddress = remoteEndPoint?.Address;
    //            RemotePort = remoteEndPoint?.Port ?? 0;
    //            var localEndPoint = LocalEndPoint;
    //            LocalIpAddress = localEndPoint?.Address;
    //            LocalPort = localEndPoint?.Port ?? 0;

    //            ConnectionIdFeature = ConnectionId;

    //            HttpRequestHeaders.Reset();
    //            HttpRequestHeaders.EncodingSelector = ServerOptions.RequestHeaderEncodingSelector;
    //            HttpRequestHeaders.ReuseHeaderValues = !ServerOptions.DisableStringReuse;
    //            HttpResponseHeaders.Reset();
    //            RequestHeaders = HttpRequestHeaders;
    //            ResponseHeaders = HttpResponseHeaders;
    //            RequestTrailers.Clear();
    //            ResponseTrailers?.Reset();
    //            RequestTrailersAvailable = false;

    //            _isLeasedMemoryInvalid = true;
    //            _hasAdvanced = false;
    //            _canWriteResponseBody = true;

    //            if (_scheme == null)
    //            {
    //                var tlsFeature = ConnectionFeatures?[typeof(ITlsConnectionFeature)];
    //                _scheme = tlsFeature != null ? SchemeHttps : SchemeHttp;
    //            }

    //            Scheme = _scheme;

    //            _manuallySetRequestAbortToken = null;

    //            // Lock to prevent CancelRequestAbortedToken from attempting to cancel a disposed CTS.
    //            CancellationTokenSource localAbortCts = null;

    //            lock (_abortLock)
    //            {
    //                _preventRequestAbortedCancellation = false;
    //                localAbortCts = _abortedCts;
    //                _abortedCts = null;
    //            }

    //            localAbortCts?.Dispose();

    //            Output?.Reset();

    //            _requestHeadersParsed = 0;

    //            _responseBytesWritten = 0;

    //            OnReset();
    //        }

    //        protected abstract void OnReset();

    //        protected abstract void ApplicationAbort();

    //        protected virtual void OnRequestProcessingEnding()
    //        {
    //        }

    //        protected virtual void OnRequestProcessingEnded()
    //        {
    //        }

    //        protected virtual void BeginRequestProcessing()
    //        {
    //        }

    //        protected virtual void OnErrorAfterResponseStarted()
    //        {
    //        }

    //        protected virtual bool BeginRead(out ValueTask<ReadResult> awaitable)
    //        {
    //            awaitable = default;
    //            return false;
    //        }

    //        protected abstract string CreateRequestId();

    //        protected abstract MessageBody CreateMessageBody();

    //        protected abstract bool TryParseRequest(ReadResult result, out bool endConnection);

    //        private void CancelRequestAbortedTokenCallback()
    //        {
    //            try
    //            {
    //                CancellationTokenSource localAbortCts = null;

    //                lock (_abortLock)
    //                {
    //                    if (_abortedCts != null && !_preventRequestAbortedCancellation)
    //                    {
    //                        localAbortCts = _abortedCts;
    //                        _abortedCts = null;
    //                    }
    //                }

    //                // If we cancel the cts, we don't dispose as people may still be using
    //                // the cts. It also isn't necessary to dispose a canceled cts.
    //                localAbortCts?.Cancel();
    //            }
    //            catch (Exception ex)
    //            {
    //                Log.ApplicationError(ConnectionId, TraceIdentifier, ex);
    //            }
    //        }

    //        protected void CancelRequestAbortedToken()
    //        {
    //            var shouldScheduleCancellation = false;

    //            lock (_abortLock)
    //            {
    //                if (_connectionAborted)
    //                {
    //                    return;
    //                }

    //                shouldScheduleCancellation = _abortedCts != null && !_preventRequestAbortedCancellation;
    //                _connectionAborted = true;
    //            }

    //            if (shouldScheduleCancellation)
    //            {
    //                // Potentially calling user code. CancelRequestAbortedToken logs any exceptions.
    //                ServiceContext.Scheduler.Schedule(state => ((HttpProtocol)state).CancelRequestAbortedTokenCallback(), this);
    //            }
    //        }

    //        protected void PoisonBody(Exception abortReason)
    //        {
    //            _bodyControl?.Abort(abortReason);
    //        }

    //        // Prevents the RequestAborted token from firing for the duration of the request.
    //        private void PreventRequestAbortedCancellation()
    //        {
    //            lock (_abortLock)
    //            {
    //                if (_connectionAborted)
    //                {
    //                    return;
    //                }

    //                _preventRequestAbortedCancellation = true;
    //            }
    //        }

    //        public virtual void OnHeader(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
    //        {
    //            IncrementRequestHeadersCount();

    //            HttpRequestHeaders.Append(name, value);
    //        }

    //        public virtual void OnHeader(int index, bool indexOnly, ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
    //        {
    //            IncrementRequestHeadersCount();

    //            // This method should be overriden in specific implementations and the base should be
    //            // called to validate the header count.
    //        }

    //        public void OnTrailer(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
    //        {
    //            IncrementRequestHeadersCount();

    //            string key = name.GetHeaderName();
    //            var valueStr = value.GetRequestHeaderString(key, HttpRequestHeaders.EncodingSelector);
    //            RequestTrailers.Append(key, valueStr);
    //        }

    //        private void IncrementRequestHeadersCount()
    //        {
    //            _requestHeadersParsed++;
    //            if (_requestHeadersParsed > ServerOptions.Limits.MaxRequestHeaderCount)
    //            {
    //                KestrelBadHttpRequestException.Throw(RequestRejectionReason.TooManyHeaders);
    //            }
    //        }

    //        public void OnHeadersComplete()
    //        {
    //            HttpRequestHeaders.OnHeadersComplete();
    //        }

    //        public void OnTrailersComplete()
    //        {
    //            RequestTrailersAvailable = true;
    //        }

    //        public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> application)
    //        {
    //            try
    //            {
    //                // We run the request processing loop in a seperate async method so per connection
    //                // exception handling doesn't complicate the generated asm for the loop.
    //                await ProcessRequests(application);
    //            }
    //            catch (BadHttpRequestException ex)
    //            {
    //                // Handle BadHttpRequestException thrown during request line or header parsing.
    //                // SetBadRequestState logs the error.
    //                SetBadRequestState(ex);
    //            }
    //            catch (ConnectionResetException ex)
    //            {
    //                // Don't log ECONNRESET errors made between requests. Browsers like IE will reset connections regularly.
    //                if (_requestProcessingStatus != RequestProcessingStatus.RequestPending)
    //                {
    //                    Log.RequestProcessingError(ConnectionId, ex);
    //                }
    //            }
    //            catch (IOException ex)
    //            {
    //                Log.RequestProcessingError(ConnectionId, ex);
    //            }
    //            catch (ConnectionAbortedException ex)
    //            {
    //                Log.RequestProcessingError(ConnectionId, ex);
    //            }
    //            catch (Exception ex)
    //            {
    //                Log.LogWarning(0, ex, CoreStrings.RequestProcessingEndError);
    //            }
    //            finally
    //            {
    //                try
    //                {
    //                    await TryProduceInvalidRequestResponse();
    //                }
    //                catch (Exception ex)
    //                {
    //                    Log.LogWarning(0, ex, CoreStrings.ConnectionShutdownError);
    //                }
    //                finally
    //                {
    //                    OnRequestProcessingEnded();
    //                }
    //            }
    //        }

    //        private async Task ProcessRequests<TContext>(IHttpApplication<TContext> application)
    //        {
    //            while (_keepAlive)
    //            {
    //                if (_context.InitialExecutionContext is null)
    //                {
    //                    // If this is a first request on a non-Http2Connection, capture a clean ExecutionContext.
    //                    _context.InitialExecutionContext = ExecutionContext.Capture();
    //                }
    //                else
    //                {
    //                    // Clear any AsyncLocals set during the request; back to a clean state ready for next request
    //                    // And/or reset to Http2Connection's ExecutionContext giving access to the connection logging scope
    //                    // and any other AsyncLocals set by connection middleware.
    //                    ExecutionContext.Restore(_context.InitialExecutionContext);
    //                }

    //                BeginRequestProcessing();

    //                var result = default(ReadResult);
    //                bool endConnection;
    //                do
    //                {
    //                    if (BeginRead(out var awaitable))
    //                    {
    //                        result = await awaitable;
    //                    }
    //                } while (!TryParseRequest(result, out endConnection));

    //                if (endConnection)
    //                {
    //                    // Connection finished, stop processing requests
    //                    return;
    //                }

    //                var messageBody = CreateMessageBody();
    //                if (!messageBody.RequestKeepAlive)
    //                {
    //                    _keepAlive = false;
    //                }

    //                IsUpgradableRequest = messageBody.RequestUpgrade;

    //                InitializeBodyControl(messageBody);


    //                var context = application.CreateContext(this);

    //                try
    //                {
    //                    KestrelEventSource.Log.RequestStart(this);

    //                    // Run the application code for this request
    //                    await application.ProcessRequestAsync(context);

    //                    // Trigger OnStarting if it hasn't been called yet and the app hasn't
    //                    // already failed. If an OnStarting callback throws we can go through
    //                    // our normal error handling in ProduceEnd.
    //                    // https://github.com/aspnet/KestrelHttpServer/issues/43
    //                    if (!HasResponseStarted && _applicationException == null && _onStarting?.Count > 0)
    //                    {
    //                        await FireOnStarting();
    //                    }

    //                    if (!_connectionAborted && !VerifyResponseContentLength(out var lengthException))
    //                    {
    //                        ReportApplicationError(lengthException);
    //                    }
    //                }
    //                catch (BadHttpRequestException ex)
    //                {
    //                    // Capture BadHttpRequestException for further processing
    //                    // This has to be caught here so StatusCode is set properly before disposing the HttpContext
    //                    // (DisposeContext logs StatusCode).
    //                    SetBadRequestState(ex);
    //                    ReportApplicationError(ex);
    //                }
    //                catch (Exception ex)
    //                {
    //                    ReportApplicationError(ex);
    //                }

    //                KestrelEventSource.Log.RequestStop(this);

    //                // At this point all user code that needs use to the request or response streams has completed.
    //                // Using these streams in the OnCompleted callback is not allowed.
    //                try
    //                {
    //                    await _bodyControl.StopAsync();
    //                }
    //                catch (Exception ex)
    //                {
    //                    // BodyControl.StopAsync() can throw if the PipeWriter was completed prior to the application writing
    //                    // enough bytes to satisfy the specified Content-Length. This risks double-logging the exception,
    //                    // but this scenario generally indicates an app bug, so I don't want to risk not logging it.
    //                    ReportApplicationError(ex);
    //                }

    //                // 4XX responses are written by TryProduceInvalidRequestResponse during connection tear down.
    //                if (_requestRejectedException == null)
    //                {
    //                    if (!_connectionAborted)
    //                    {
    //                        // Call ProduceEnd() before consuming the rest of the request body to prevent
    //                        // delaying clients waiting for the chunk terminator:
    //                        //
    //                        // https://github.com/dotnet/corefx/issues/17330#issuecomment-288248663
    //                        //
    //                        // This also prevents the 100 Continue response from being sent if the app
    //                        // never tried to read the body.
    //                        // https://github.com/aspnet/KestrelHttpServer/issues/2102
    //                        //
    //                        // ProduceEnd() must be called before _application.DisposeContext(), to ensure
    //                        // HttpContext.Response.StatusCode is correctly set when
    //                        // IHttpContextFactory.Dispose(HttpContext) is called.
    //                        await ProduceEnd();
    //                    }
    //                    else if (!HasResponseStarted)
    //                    {
    //                        // If the request was aborted and no response was sent, there's no
    //                        // meaningful status code to log.
    //                        StatusCode = 0;
    //                    }
    //                }

    //                if (_onCompleted?.Count > 0)
    //                {
    //                    await FireOnCompleted();
    //                }

    //                application.DisposeContext(context, _applicationException);

    //                // Even for non-keep-alive requests, try to consume the entire body to avoid RSTs.
    //                if (!_connectionAborted && _requestRejectedException == null && !messageBody.IsEmpty)
    //                {
    //                    await messageBody.ConsumeAsync();
    //                }

    //                if (HasStartedConsumingRequestBody)
    //                {
    //                    await messageBody.StopAsync();
    //                }
    //            }
    //        }

    //        public void OnStarting(Func<object, Task> callback, object state)
    //        {
    //            if (HasResponseStarted)
    //            {
    //                ThrowResponseAlreadyStartedException(nameof(OnStarting));
    //            }

    //            if (_onStarting == null)
    //            {
    //                _onStarting = new Stack<KeyValuePair<Func<object, Task>, object>>();
    //            }
    //            _onStarting.Push(new KeyValuePair<Func<object, Task>, object>(callback, state));
    //        }

    //        public void OnCompleted(Func<object, Task> callback, object state)
    //        {
    //            if (_onCompleted == null)
    //            {
    //                _onCompleted = new Stack<KeyValuePair<Func<object, Task>, object>>();
    //            }
    //            _onCompleted.Push(new KeyValuePair<Func<object, Task>, object>(callback, state));
    //        }

    //        protected Task FireOnStarting()
    //        {
    //            var onStarting = _onStarting;
    //            if (onStarting?.Count > 0)
    //            {
    //                return ProcessEvents(this, onStarting);
    //            }

    //            return Task.CompletedTask;

    //            static async Task ProcessEvents(HttpProtocol protocol, Stack<KeyValuePair<Func<object, Task>, object>> events)
    //            {
    //                // Try/Catch is outside the loop as any error that occurs is before the request starts.
    //                // So we want to report it as an ApplicationError to fail the request and not process more events.
    //                try
    //                {
    //                    while (events.TryPop(out var entry))
    //                    {
    //                        await entry.Key.Invoke(entry.Value);
    //                    }
    //                }
    //                catch (Exception ex)
    //                {
    //                    protocol.ReportApplicationError(ex);
    //                }
    //            }
    //        }

    //        protected Task FireOnCompleted()
    //        {
    //            var onCompleted = _onCompleted;
    //            if (onCompleted?.Count > 0)
    //            {
    //                return ProcessEvents(this, onCompleted);
    //            }

    //            return Task.CompletedTask;

    //            static async Task ProcessEvents(HttpProtocol protocol, Stack<KeyValuePair<Func<object, Task>, object>> events)
    //            {
    //                // Try/Catch is inside the loop as any error that occurs is after the request has finished.
    //                // So we will just log it and keep processing the events, as the completion has already happened.
    //                while (events.TryPop(out var entry))
    //                {
    //                    try
    //                    {
    //                        await entry.Key.Invoke(entry.Value);
    //                    }
    //                    catch (Exception ex)
    //                    {
    //                        protocol.Log.ApplicationError(protocol.ConnectionId, protocol.TraceIdentifier, ex);
    //                    }
    //                }
    //            }
    //        }

    //        private void VerifyAndUpdateWrite(int count)
    //        {
    //            var responseHeaders = HttpResponseHeaders;

    //            if (responseHeaders != null &&
    //                !responseHeaders.HasTransferEncoding &&
    //                responseHeaders.ContentLength.HasValue &&
    //                _responseBytesWritten + count > responseHeaders.ContentLength.Value)
    //            {
    //                _keepAlive = false;
    //                ThrowTooManyBytesWritten(count);
    //            }

    //            _responseBytesWritten += count;
    //        }

    //        [StackTraceHidden]
    //        private void ThrowTooManyBytesWritten(int count)
    //        {
    //            throw GetTooManyBytesWrittenException(count);
    //        }

    //        [MethodImpl(MethodImplOptions.NoInlining)]
    //        private InvalidOperationException GetTooManyBytesWrittenException(int count)
    //        {
    //            var responseHeaders = HttpResponseHeaders;
    //            return new InvalidOperationException(
    //                CoreStrings.FormatTooManyBytesWritten(_responseBytesWritten + count, responseHeaders.ContentLength.Value));
    //        }

    //        private void CheckLastWrite()
    //        {
    //            var responseHeaders = HttpResponseHeaders;

    //            // Prevent firing request aborted token if this is the last write, to avoid
    //            // aborting the request if the app is still running when the client receives
    //            // the final bytes of the response and gracefully closes the connection.
    //            //
    //            // Called after VerifyAndUpdateWrite(), so _responseBytesWritten has already been updated.
    //            if (responseHeaders != null &&
    //                !responseHeaders.HasTransferEncoding &&
    //                responseHeaders.ContentLength.HasValue &&
    //                _responseBytesWritten == responseHeaders.ContentLength.Value)
    //            {
    //                PreventRequestAbortedCancellation();
    //            }
    //        }

    //        protected bool VerifyResponseContentLength(out Exception ex)
    //        {
    //            var responseHeaders = HttpResponseHeaders;

    //            if (Method != HttpMethod.Head &&
    //                StatusCode != StatusCodes.Status304NotModified &&
    //                !responseHeaders.HasTransferEncoding &&
    //                responseHeaders.ContentLength.HasValue &&
    //                _responseBytesWritten < responseHeaders.ContentLength.Value)
    //            {
    //                // We need to close the connection if any bytes were written since the client
    //                // cannot be certain of how many bytes it will receive.
    //                if (_responseBytesWritten > 0)
    //                {
    //                    _keepAlive = false;
    //                }

    //                ex = new InvalidOperationException(
    //                    CoreStrings.FormatTooFewBytesWritten(_responseBytesWritten, responseHeaders.ContentLength.Value));
    //                return false;
    //            }

    //            ex = null;
    //            return true;
    //        }

    //        public void ProduceContinue()
    //        {
    //            if (HasResponseStarted)
    //            {
    //                return;
    //            }

    //            if (_httpVersion != Http.HttpVersion.Http10 &&
    //                RequestHeaders.TryGetValue(HeaderNames.Expect, out var expect) &&
    //                (expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
    //            {
    //                Output.Write100ContinueAsync().GetAwaiter().GetResult();
    //            }
    //        }

    //        public Task InitializeResponseAsync(int firstWriteByteCount)
    //        {
    //            var startingTask = FireOnStarting();
    //            if (!startingTask.IsCompletedSuccessfully)
    //            {
    //                return InitializeResponseAwaited(startingTask, firstWriteByteCount);
    //            }

    //            VerifyInitializeState(firstWriteByteCount);

    //            ProduceStart(appCompleted: false);

    //            return Task.CompletedTask;
    //        }

    //        [MethodImpl(MethodImplOptions.NoInlining)]
    //        public async Task InitializeResponseAwaited(Task startingTask, int firstWriteByteCount)
    //        {
    //            await startingTask;

    //            VerifyInitializeState(firstWriteByteCount);

    //            ProduceStart(appCompleted: false);
    //        }

    //        private HttpResponseHeaders InitializeResponseFirstWrite(int firstWriteByteCount)
    //        {
    //            VerifyInitializeState(firstWriteByteCount);

    //            var responseHeaders = CreateResponseHeaders(appCompleted: false);

    //            // InitializeResponse can only be called if we are just about to Flush the headers
    //            _requestProcessingStatus = RequestProcessingStatus.HeadersFlushed;

    //            return responseHeaders;
    //        }

    //        private void ProduceStart(bool appCompleted)
    //        {
    //            if (HasResponseStarted)
    //            {
    //                return;
    //            }

    //            _isLeasedMemoryInvalid = true;

    //            _requestProcessingStatus = RequestProcessingStatus.HeadersCommitted;

    //            var responseHeaders = CreateResponseHeaders(appCompleted);

    //            Output.WriteResponseHeaders(StatusCode, ReasonPhrase, responseHeaders, _autoChunk, appCompleted);
    //        }

    //        private void VerifyInitializeState(int firstWriteByteCount)
    //        {
    //            if (_applicationException != null)
    //            {
    //                ThrowResponseAbortedException();
    //            }

    //            VerifyAndUpdateWrite(firstWriteByteCount);
    //        }

    //        protected Task TryProduceInvalidRequestResponse()
    //        {
    //            // If _requestAborted is set, the connection has already been closed.
    //            if (_requestRejectedException != null && !_connectionAborted)
    //            {
    //                return ProduceEnd();
    //            }

    //            return Task.CompletedTask;
    //        }

    //        protected Task ProduceEnd()
    //        {
    //            if (HasResponseCompleted)
    //            {
    //                return Task.CompletedTask;
    //            }

    //            _isLeasedMemoryInvalid = true;

    //            if (_requestRejectedException != null || _applicationException != null)
    //            {
    //                if (HasResponseStarted)
    //                {
    //                    // We can no longer change the response, so we simply close the connection.
    //                    _keepAlive = false;
    //                    OnErrorAfterResponseStarted();
    //                    return Task.CompletedTask;
    //                }

    //                // If the request was rejected, the error state has already been set by SetBadRequestState and
    //                // that should take precedence.
    //                if (_requestRejectedException != null)
    //                {
    //                    SetErrorResponseException(_requestRejectedException);
    //                }
    //                else
    //                {
    //                    // 500 Internal Server Error
    //                    SetErrorResponseHeaders(statusCode: StatusCodes.Status500InternalServerError);
    //                }
    //            }

    //            if (!HasResponseStarted)
    //            {
    //                ProduceStart(appCompleted: true);
    //            }

    //            return WriteSuffix();
    //        }

    //        private Task WriteSuffix()
    //        {
    //            if (_autoChunk || _httpVersion >= Http.HttpVersion.Http2)
    //            {
    //                // For the same reason we call CheckLastWrite() in Content-Length responses.
    //                PreventRequestAbortedCancellation();
    //            }

    //            var writeTask = Output.WriteStreamSuffixAsync();

    //            if (!writeTask.IsCompletedSuccessfully)
    //            {
    //                return WriteSuffixAwaited(writeTask);
    //            }

    //            _requestProcessingStatus = RequestProcessingStatus.ResponseCompleted;

    //            if (_keepAlive)
    //            {
    //                Log.ConnectionKeepAlive(ConnectionId);
    //            }

    //            if (Method == HttpMethod.Head && _responseBytesWritten > 0)
    //            {
    //                Log.ConnectionHeadResponseBodyWrite(ConnectionId, _responseBytesWritten);
    //            }

    //            return Task.CompletedTask;
    //        }

    //        private async Task WriteSuffixAwaited(ValueTask<FlushResult> writeTask)
    //        {
    //            _requestProcessingStatus = RequestProcessingStatus.HeadersFlushed;

    //            await writeTask;

    //            _requestProcessingStatus = RequestProcessingStatus.ResponseCompleted;

    //            if (_keepAlive)
    //            {
    //                Log.ConnectionKeepAlive(ConnectionId);
    //            }

    //            if (Method == HttpMethod.Head && _responseBytesWritten > 0)
    //            {
    //                Log.ConnectionHeadResponseBodyWrite(ConnectionId, _responseBytesWritten);
    //            }
    //        }

    //        private HttpResponseHeaders CreateResponseHeaders(bool appCompleted)
    //        {
    //            var responseHeaders = HttpResponseHeaders;
    //            var hasConnection = responseHeaders.HasConnection;
    //            var hasTransferEncoding = responseHeaders.HasTransferEncoding;

    //            if (_keepAlive &&
    //                hasConnection &&
    //                (HttpHeaders.ParseConnection(responseHeaders.HeaderConnection) & ConnectionOptions.KeepAlive) == 0)
    //            {
    //                _keepAlive = false;
    //            }

    //            // https://tools.ietf.org/html/rfc7230#section-3.3.1
    //            // If any transfer coding other than
    //            // chunked is applied to a response payload body, the sender MUST either
    //            // apply chunked as the final transfer coding or terminate the message
    //            // by closing the connection.
    //            if (hasTransferEncoding &&
    //                HttpHeaders.GetFinalTransferCoding(responseHeaders.HeaderTransferEncoding) != TransferCoding.Chunked)
    //            {
    //                _keepAlive = false;
    //            }

    //            // Set whether response can have body
    //            _canWriteResponseBody = CanWriteResponseBody();

    //            if (!_canWriteResponseBody && hasTransferEncoding)
    //            {
    //                RejectNonBodyTransferEncodingResponse(appCompleted);
    //            }
    //            else if (StatusCode == StatusCodes.Status101SwitchingProtocols)
    //            {
    //                _keepAlive = false;
    //            }
    //            else if (!hasTransferEncoding && !responseHeaders.ContentLength.HasValue)
    //            {
    //                if ((appCompleted || !_canWriteResponseBody) && !_hasAdvanced) // Avoid setting contentLength of 0 if we wrote data before calling CreateResponseHeaders
    //                {
    //                    // Don't set the Content-Length header automatically for HEAD requests, 204 responses, or 304 responses.
    //                    if (CanAutoSetContentLengthZeroResponseHeader())
    //                    {
    //                        // Since the app has completed writing or cannot write to the response, we can safely set the Content-Length to 0.
    //                        responseHeaders.ContentLength = 0;
    //                    }
    //                }
    //                // Note for future reference: never change this to set _autoChunk to true on HTTP/1.0
    //                // connections, even if we were to infer the client supports it because an HTTP/1.0 request
    //                // was received that used chunked encoding. Sending a chunked response to an HTTP/1.0
    //                // client would break compliance with RFC 7230 (section 3.3.1):
    //                //
    //                // A server MUST NOT send a response containing Transfer-Encoding unless the corresponding
    //                // request indicates HTTP/1.1 (or later).
    //                //
    //                // This also covers HTTP/2, which forbids chunked encoding in RFC 7540 (section 8.1:
    //                //
    //                // The chunked transfer encoding defined in Section 4.1 of [RFC7230] MUST NOT be used in HTTP/2.
    //                else if (_httpVersion == Http.HttpVersion.Http11)
    //                {
    //                    _autoChunk = true;
    //                    responseHeaders.SetRawTransferEncoding("chunked", _bytesTransferEncodingChunked);
    //                }
    //                else
    //                {
    //                    _keepAlive = false;
    //                }
    //            }

    //            responseHeaders.SetReadOnly();

    //            if (!hasConnection && _httpVersion < Http.HttpVersion.Http2)
    //            {
    //                if (!_keepAlive)
    //                {
    //                    responseHeaders.SetRawConnection("close", _bytesConnectionClose);
    //                }
    //                else if (_httpVersion == Http.HttpVersion.Http10)
    //                {
    //                    responseHeaders.SetRawConnection("keep-alive", _bytesConnectionKeepAlive);
    //                }
    //            }

    //            // TODO allow customization of this.
    //            if (ServerOptions.EnableAltSvc && _httpVersion < Http.HttpVersion.Http3)
    //            {
    //                foreach (var option in ServerOptions.ListenOptions)
    //                {
    //                    if ((option.Protocols & HttpProtocols.Http3) == HttpProtocols.Http3)
    //                    {
    //                        responseHeaders.HeaderAltSvc = $"h3-25=\":{option.IPEndPoint.Port}\"; ma=84600";
    //                        break;
    //                    }
    //                }
    //            }

    //            if (ServerOptions.AddServerHeader && !responseHeaders.HasServer)
    //            {
    //                responseHeaders.SetRawServer(Constants.ServerName, _bytesServer);
    //            }

    //            if (!responseHeaders.HasDate)
    //            {
    //                var dateHeaderValues = DateHeaderValueManager.GetDateHeaderValues();
    //                responseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);
    //            }

    //            return responseHeaders;
    //        }

    //        private bool CanWriteResponseBody()
    //        {
    //            // List of status codes taken from Microsoft.Net.Http.Server.Response
    //            return Method != HttpMethod.Head &&
    //                   StatusCode != StatusCodes.Status204NoContent &&
    //                   StatusCode != StatusCodes.Status205ResetContent &&
    //                   StatusCode != StatusCodes.Status304NotModified;
    //        }

    //        private bool CanAutoSetContentLengthZeroResponseHeader()
    //        {
    //            return Method != HttpMethod.Head &&
    //                   StatusCode != StatusCodes.Status204NoContent &&
    //                   StatusCode != StatusCodes.Status304NotModified;
    //        }

    //        private static void ThrowResponseAlreadyStartedException(string value)
    //        {
    //            throw new InvalidOperationException(CoreStrings.FormatParameterReadOnlyAfterResponseStarted(value));
    //        }

    //        private void RejectNonBodyTransferEncodingResponse(bool appCompleted)
    //        {
    //            var ex = new InvalidOperationException(CoreStrings.FormatHeaderNotAllowedOnResponse("Transfer-Encoding", StatusCode));
    //            if (!appCompleted)
    //            {
    //                // Back out of header creation surface exception in user code
    //                _requestProcessingStatus = RequestProcessingStatus.AppStarted;
    //                throw ex;
    //            }
    //            else
    //            {
    //                ReportApplicationError(ex);

    //                // 500 Internal Server Error
    //                SetErrorResponseHeaders(statusCode: StatusCodes.Status500InternalServerError);
    //            }
    //        }

    //        private void SetErrorResponseException(BadHttpRequestException ex)
    //        {
    //            SetErrorResponseHeaders(ex.StatusCode);

    //#pragma warning disable CS0618 // Type or member is obsolete
    //            if (ex is Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException kestrelEx && !StringValues.IsNullOrEmpty(kestrelEx.AllowedHeader))
    //#pragma warning restore CS0618 // Type or member is obsolete
    //            {
    //                HttpResponseHeaders.HeaderAllow = kestrelEx.AllowedHeader;
    //            }
    //        }

    //        private void SetErrorResponseHeaders(int statusCode)
    //        {
    //            Debug.Assert(!HasResponseStarted, $"{nameof(SetErrorResponseHeaders)} called after response had already started.");

    //            StatusCode = statusCode;
    //            ReasonPhrase = null;

    //            var responseHeaders = HttpResponseHeaders;
    //            responseHeaders.Reset();
    //            ResponseTrailers?.Reset();
    //            var dateHeaderValues = DateHeaderValueManager.GetDateHeaderValues();

    //            responseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);

    //            responseHeaders.ContentLength = 0;

    //            if (ServerOptions.AddServerHeader)
    //            {
    //                responseHeaders.SetRawServer(Constants.ServerName, _bytesServer);
    //            }
    //        }

    //        public void HandleNonBodyResponseWrite()
    //        {
    //            // Writes to HEAD response are ignored and logged at the end of the request
    //            if (Method != HttpMethod.Head)
    //            {
    //                ThrowWritingToResponseBodyNotSupported();
    //            }
    //        }

    //        [StackTraceHidden]
    //        private void ThrowWritingToResponseBodyNotSupported()
    //        {
    //            // Throw Exception for 204, 205, 304 responses.
    //            throw new InvalidOperationException(CoreStrings.FormatWritingToResponseBodyNotSupported(StatusCode));
    //        }

    //        [StackTraceHidden]
    //        private void ThrowResponseAbortedException()
    //        {
    //            throw new ObjectDisposedException(CoreStrings.UnhandledApplicationException, _applicationException);
    //        }

    //        [StackTraceHidden]
    //        public void ThrowRequestTargetRejected(Span<byte> target)
    //            => throw GetInvalidRequestTargetException(target);

    //        [MethodImpl(MethodImplOptions.NoInlining)]
    //        private BadHttpRequestException GetInvalidRequestTargetException(ReadOnlySpan<byte> target)
    //            => KestrelBadHttpRequestException.GetException(
    //                RequestRejectionReason.InvalidRequestTarget,
    //                Log.IsEnabled(LogLevel.Information)
    //                    ? target.GetAsciiStringEscaped(Constants.MaxExceptionDetailSize)
    //                    : string.Empty);

    //        public void SetBadRequestState(BadHttpRequestException ex)
    //        {
    //            Log.ConnectionBadRequest(ConnectionId, ex);

    //            if (!HasResponseStarted)
    //            {
    //                SetErrorResponseException(ex);
    //            }

    //            _keepAlive = false;
    //            _requestRejectedException = ex;
    //        }

    //        public void ReportApplicationError(Exception ex)
    //        {
    //            // ReportApplicationError can be called with a null exception from MessageBody
    //            if (ex == null)
    //            {
    //                return;
    //            }

    //            if (_applicationException == null)
    //            {
    //                _applicationException = ex;
    //            }
    //            else if (_applicationException is AggregateException)
    //            {
    //                _applicationException = new AggregateException(_applicationException, ex).Flatten();
    //            }
    //            else
    //            {
    //                _applicationException = new AggregateException(_applicationException, ex);
    //            }

    //            Log.ApplicationError(ConnectionId, TraceIdentifier, ex);
    //        }

    //        public void Advance(int bytes)
    //        {
    //            if (bytes < 0)
    //            {
    //                throw new ArgumentOutOfRangeException(nameof(bytes));
    //            }
    //            else if (bytes > 0)
    //            {
    //                _hasAdvanced = true;
    //            }

    //            if (_isLeasedMemoryInvalid)
    //            {
    //                throw new InvalidOperationException("Invalid ordering of calling StartAsync or CompleteAsync and Advance.");
    //            }

    //            if (_canWriteResponseBody)
    //            {
    //                VerifyAndUpdateWrite(bytes);
    //                Output.Advance(bytes);
    //            }
    //            else
    //            {
    //                HandleNonBodyResponseWrite();
    //                // For HEAD requests, we still use the number of bytes written for logging
    //                // how many bytes were written.
    //                VerifyAndUpdateWrite(bytes);
    //            }
    //        }

    //        public Memory<byte> GetMemory(int sizeHint = 0)
    //        {
    //            _isLeasedMemoryInvalid = false;
    //            return Output.GetMemory(sizeHint);
    //        }

    //        public Span<byte> GetSpan(int sizeHint = 0)
    //        {
    //            _isLeasedMemoryInvalid = false;
    //            return Output.GetSpan(sizeHint);
    //        }

    //        public ValueTask<FlushResult> FlushPipeAsync(CancellationToken cancellationToken)
    //        {
    //            if (!HasResponseStarted)
    //            {
    //                var initializeTask = InitializeResponseAsync(0);
    //                if (!initializeTask.IsCompletedSuccessfully)
    //                {
    //                    return FlushAsyncAwaited(initializeTask, cancellationToken);
    //                }
    //            }

    //            return Output.FlushAsync(cancellationToken);
    //        }

    //        public void CancelPendingFlush()
    //        {
    //            Output.CancelPendingFlush();
    //        }

    //        public Task CompleteAsync(Exception exception = null)
    //        {
    //            if (exception != null)
    //            {
    //                var wrappedException = new ConnectionAbortedException("The BodyPipe was completed with an exception.", exception);
    //                ReportApplicationError(wrappedException);

    //                if (HasResponseStarted)
    //                {
    //                    ApplicationAbort();
    //                }
    //            }

    //            // Finalize headers
    //            if (!HasResponseStarted)
    //            {
    //                var onStartingTask = FireOnStarting();
    //                if (!onStartingTask.IsCompletedSuccessfully)
    //                {
    //                    return CompleteAsyncAwaited(onStartingTask);
    //                }
    //            }

    //            // Flush headers, body, trailers...
    //            if (!HasResponseCompleted)
    //            {
    //                if (!VerifyResponseContentLength(out var lengthException))
    //                {
    //                    // Try to throw this exception from CompleteAsync() instead of CompleteAsyncAwaited() if possible,
    //                    // so it can be observed by BodyWriter.Complete(). If this isn't possible because an
    //                    // async OnStarting callback hadn't yet run, it's OK, since the Exception will be observed with
    //                    // the call to _bodyControl.StopAsync() in ProcessRequests().
    //                    ThrowException(lengthException);
    //                }

    //                return ProduceEnd();
    //            }

    //            return Task.CompletedTask;
    //        }

    //        private async Task CompleteAsyncAwaited(Task onStartingTask)
    //        {
    //            await onStartingTask;

    //            if (!HasResponseCompleted)
    //            {
    //                if (!VerifyResponseContentLength(out var lengthException))
    //                {
    //                    ThrowException(lengthException);
    //                }

    //                await ProduceEnd();
    //            }
    //        }

    //        [StackTraceHidden]
    //        private static void ThrowException(Exception exception)
    //        {
    //            throw exception;
    //        }

    //        public ValueTask<FlushResult> WritePipeAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
    //        {
    //            // For the first write, ensure headers are flushed if WriteDataAsync isn't called.
    //            if (!HasResponseStarted)
    //            {
    //                return FirstWriteAsync(data, cancellationToken);
    //            }
    //            else
    //            {
    //                VerifyAndUpdateWrite(data.Length);
    //            }

    //            if (_canWriteResponseBody)
    //            {
    //                if (_autoChunk)
    //                {
    //                    if (data.Length == 0)
    //                    {
    //                        return default;
    //                    }

    //                    return Output.WriteChunkAsync(data.Span, cancellationToken);
    //                }
    //                else
    //                {
    //                    CheckLastWrite();
    //                    return Output.WriteDataToPipeAsync(data.Span, cancellationToken: cancellationToken);
    //                }
    //            }
    //            else
    //            {
    //                HandleNonBodyResponseWrite();
    //                return default;
    //            }
    //        }

    //        private ValueTask<FlushResult> FirstWriteAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
    //        {
    //            Debug.Assert(!HasResponseStarted);

    //            var startingTask = FireOnStarting();
    //            if (!startingTask.IsCompletedSuccessfully)
    //            {
    //                return FirstWriteAsyncAwaited(startingTask, data, cancellationToken);
    //            }

    //            return FirstWriteAsyncInternal(data, cancellationToken);
    //        }

    //        private async ValueTask<FlushResult> FirstWriteAsyncAwaited(Task initializeTask, ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
    //        {
    //            await initializeTask;

    //            return await FirstWriteAsyncInternal(data, cancellationToken);
    //        }

    //        private ValueTask<FlushResult> FirstWriteAsyncInternal(ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
    //        {
    //            var responseHeaders = InitializeResponseFirstWrite(data.Length);

    //            if (_canWriteResponseBody)
    //            {
    //                if (_autoChunk)
    //                {
    //                    if (data.Length == 0)
    //                    {
    //                        Output.WriteResponseHeaders(StatusCode, ReasonPhrase, responseHeaders, _autoChunk, appCompleted: false);
    //                        return Output.FlushAsync(cancellationToken);
    //                    }

    //                    return Output.FirstWriteChunkedAsync(StatusCode, ReasonPhrase, responseHeaders, _autoChunk, data.Span, cancellationToken);
    //                }
    //                else
    //                {
    //                    CheckLastWrite();
    //                    return Output.FirstWriteAsync(StatusCode, ReasonPhrase, responseHeaders, _autoChunk, data.Span, cancellationToken);
    //                }
    //            }
    //            else
    //            {
    //                Output.WriteResponseHeaders(StatusCode, ReasonPhrase, responseHeaders, _autoChunk, appCompleted: false);
    //                HandleNonBodyResponseWrite();
    //                return Output.FlushAsync(cancellationToken);
    //            }
    //        }

    //        public Task FlushAsync(CancellationToken cancellationToken = default)
    //        {
    //            return FlushPipeAsync(cancellationToken).GetAsTask();
    //        }

    //        [MethodImpl(MethodImplOptions.NoInlining)]
    //        private async ValueTask<FlushResult> FlushAsyncAwaited(Task initializeTask, CancellationToken cancellationToken)
    //        {
    //            await initializeTask;
    //            return await Output.FlushAsync(cancellationToken);
    //        }

    //        public Task WriteAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken = default)
    //        {
    //            return WritePipeAsync(data, cancellationToken).GetAsTask();
    //        }

    //        public async ValueTask<FlushResult> WriteAsyncAwaited(Task initializeTask, ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
    //        {
    //            await initializeTask;

    //            // WriteAsyncAwaited is only called for the first write to the body.
    //            // Ensure headers are flushed if Write(Chunked)Async isn't called.
    //            if (_canWriteResponseBody)
    //            {
    //                if (_autoChunk)
    //                {
    //                    if (data.Length == 0)
    //                    {
    //                        return await Output.FlushAsync(cancellationToken);
    //                    }

    //                    return await Output.WriteChunkAsync(data.Span, cancellationToken);
    //                }
    //                else
    //                {
    //                    CheckLastWrite();
    //                    return await Output.WriteDataToPipeAsync(data.Span, cancellationToken: cancellationToken);
    //                }
    //            }
    //            else
    //            {
    //                HandleNonBodyResponseWrite();
    //                return await Output.FlushAsync(cancellationToken);
    //            }
    //        }
    //    }

    //internal partial class Http1Connection : HttpProtocol, IRequestProcessor, IHttpOutputAborter
    //{
    //    private const byte ByteAsterisk = (byte)'*';
    //    private const byte ByteForwardSlash = (byte)'/';
    //    private const string Asterisk = "*";
    //    private const string ForwardSlash = "/";

    //    private readonly HttpConnectionContext _context;
    //    private readonly IHttpParser<Http1ParsingHandler> _parser;
    //    private readonly Http1OutputProducer _http1Output;
    //    protected readonly long _keepAliveTicks;
    //    private readonly long _requestHeadersTimeoutTicks;

    //    private volatile bool _requestTimedOut;
    //    private uint _requestCount;

    //    private HttpRequestTarget _requestTargetForm = HttpRequestTarget.Unknown;
    //    private Uri _absoluteRequestTarget;

    //    // The _parsed fields cache the Path, QueryString, RawTarget, and/or _absoluteRequestTarget
    //    // from the previous request when DisableStringReuse is false.
    //    private string _parsedPath = null;
    //    private string _parsedQueryString = null;
    //    private string _parsedRawTarget = null;
    //    private Uri _parsedAbsoluteRequestTarget;

    //    private long _remainingRequestHeadersBytesAllowed;

    //    public Http1Connection(HttpConnectionContext context)
    //    {
    //        Initialize(context);

    //        _context = context;
    //        _parser = ServiceContext.HttpParser;
    //        _keepAliveTicks = ServerOptions.Limits.KeepAliveTimeout.Ticks;
    //        _requestHeadersTimeoutTicks = ServerOptions.Limits.RequestHeadersTimeout.Ticks;

    //        _http1Output = new Http1OutputProducer(
    //            _context.Transport.Output,
    //            _context.ConnectionId,
    //            _context.ConnectionContext,
    //            _context.MemoryPool,
    //            _context.ServiceContext.Log,
    //            _context.TimeoutControl,
    //            minResponseDataRateFeature: this,
    //            outputAborter: this);

    //        Input = _context.Transport.Input;
    //        Output = _http1Output;
    //        MemoryPool = _context.MemoryPool;
    //    }

    //    public PipeReader Input { get; }

    //    public bool RequestTimedOut => _requestTimedOut;

    //    public MinDataRate MinResponseDataRate { get; set; }

    //    public MemoryPool<byte> MemoryPool { get; }

    //    protected override void OnRequestProcessingEnded()
    //    {
    //        if (IsUpgraded)
    //        {
    //            KestrelEventSource.Log.RequestUpgradedStop(this);

    //            ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
    //        }

    //        TimeoutControl.StartDrainTimeout(MinResponseDataRate, ServerOptions.Limits.MaxResponseBufferSize);

    //        // Prevent RequestAborted from firing. Free up unneeded feature references.
    //        Reset();

    //        _http1Output.Dispose();
    //    }

    //    public void OnInputOrOutputCompleted()
    //    {
    //        _http1Output.Abort(new ConnectionAbortedException(CoreStrings.ConnectionAbortedByClient));
    //        CancelRequestAbortedToken();
    //    }

    //    /// <summary>
    //    /// Immediately kill the connection and poison the request body stream with an error.
    //    /// </summary>
    //    public void Abort(ConnectionAbortedException abortReason)
    //    {
    //        _http1Output.Abort(abortReason);
    //        CancelRequestAbortedToken();
    //        PoisonBody(abortReason);
    //    }

    //    protected override void ApplicationAbort()
    //    {
    //        Log.ApplicationAbortedConnection(ConnectionId, TraceIdentifier);
    //        Abort(new ConnectionAbortedException(CoreStrings.ConnectionAbortedByApplication));
    //    }

    //    /// <summary>
    //    /// Stops the request processing loop between requests.
    //    /// Called on all active connections when the server wants to initiate a shutdown
    //    /// and after a keep-alive timeout.
    //    /// </summary>
    //    public void StopProcessingNextRequest()
    //    {
    //        _keepAlive = false;
    //        Input.CancelPendingRead();
    //    }

    //    public void SendTimeoutResponse()
    //    {
    //        _requestTimedOut = true;
    //        Input.CancelPendingRead();
    //    }

    //    public void HandleRequestHeadersTimeout()
    //        => SendTimeoutResponse();

    //    public void HandleReadDataRateTimeout()
    //    {
    //        Log.RequestBodyMinimumDataRateNotSatisfied(ConnectionId, TraceIdentifier, MinRequestBodyDataRate.BytesPerSecond);
    //        SendTimeoutResponse();
    //    }

    //    public bool ParseRequest(ref SequenceReader<byte> reader)
    //    {
    //        switch (_requestProcessingStatus)
    //        {
    //            case RequestProcessingStatus.RequestPending:
    //                if (reader.End)
    //                {
    //                    break;
    //                }

    //                TimeoutControl.ResetTimeout(_requestHeadersTimeoutTicks, TimeoutReason.RequestHeaders);

    //                _requestProcessingStatus = RequestProcessingStatus.ParsingRequestLine;
    //                goto case RequestProcessingStatus.ParsingRequestLine;
    //            case RequestProcessingStatus.ParsingRequestLine:
    //                if (TakeStartLine(ref reader))
    //                {
    //                    _requestProcessingStatus = RequestProcessingStatus.ParsingHeaders;
    //                    goto case RequestProcessingStatus.ParsingHeaders;
    //                }
    //                else
    //                {
    //                    break;
    //                }
    //            case RequestProcessingStatus.ParsingHeaders:
    //                if (TakeMessageHeaders(ref reader, trailers: false))
    //                {
    //                    _requestProcessingStatus = RequestProcessingStatus.AppStarted;
    //                    // Consumed preamble
    //                    return true;
    //                }
    //                break;
    //        }

    //        // Haven't completed consuming preamble
    //        return false;
    //    }

    //    public bool TakeStartLine(ref SequenceReader<byte> reader)
    //    {
    //        // Make sure the buffer is limited
    //        if (reader.Remaining >= ServerOptions.Limits.MaxRequestLineSize)
    //        {
    //            // Input oversize, cap amount checked
    //            return TrimAndTakeStartLine(ref reader);
    //        }

    //        return _parser.ParseRequestLine(new Http1ParsingHandler(this), ref reader);

    //        bool TrimAndTakeStartLine(ref SequenceReader<byte> reader)
    //        {
    //            var trimmedBuffer = reader.Sequence.Slice(reader.Position, ServerOptions.Limits.MaxRequestLineSize);
    //            var trimmedReader = new SequenceReader<byte>(trimmedBuffer);

    //            if (!_parser.ParseRequestLine(new Http1ParsingHandler(this), ref trimmedReader))
    //            {
    //                // We read the maximum allowed but didn't complete the start line.
    //                KestrelBadHttpRequestException.Throw(RequestRejectionReason.RequestLineTooLong);
    //            }

    //            reader.Advance(trimmedReader.Consumed);
    //            return true;
    //        }
    //    }

    //    public bool TakeMessageHeaders(ref SequenceReader<byte> reader, bool trailers)
    //    {
    //        // Make sure the buffer is limited
    //        if (reader.Remaining > _remainingRequestHeadersBytesAllowed)
    //        {
    //            // Input oversize, cap amount checked
    //            return TrimAndTakeMessageHeaders(ref reader, trailers);
    //        }

    //        var alreadyConsumed = reader.Consumed;

    //        try
    //        {
    //            var result = _parser.ParseHeaders(new Http1ParsingHandler(this, trailers), ref reader);
    //            if (result)
    //            {
    //                TimeoutControl.CancelTimeout();
    //            }

    //            return result;
    //        }
    //        finally
    //        {
    //            _remainingRequestHeadersBytesAllowed -= reader.Consumed - alreadyConsumed;
    //        }

    //        bool TrimAndTakeMessageHeaders(ref SequenceReader<byte> reader, bool trailers)
    //        {
    //            var trimmedBuffer = reader.Sequence.Slice(reader.Position, _remainingRequestHeadersBytesAllowed);
    //            var trimmedReader = new SequenceReader<byte>(trimmedBuffer);
    //            try
    //            {
    //                if (!_parser.ParseHeaders(new Http1ParsingHandler(this, trailers), ref trimmedReader))
    //                {
    //                    // We read the maximum allowed but didn't complete the headers.
    //                    KestrelBadHttpRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize);
    //                }

    //                TimeoutControl.CancelTimeout();

    //                reader.Advance(trimmedReader.Consumed);

    //                return true;
    //            }
    //            finally
    //            {
    //                _remainingRequestHeadersBytesAllowed -= trimmedReader.Consumed;
    //            }
    //        }
    //    }

    //    public void OnStartLine(HttpVersionAndMethod versionAndMethod, TargetOffsetPathLength targetPath, Span<byte> startLine)
    //    {
    //        var targetStart = targetPath.Offset;
    //        // Slice out target
    //        var target = startLine[targetStart..];
    //        Debug.Assert(target.Length != 0, "Request target must be non-zero length");
    //        var method = versionAndMethod.Method;
    //        var ch = target[0];
    //        if (ch == ByteForwardSlash)
    //        {
    //            // origin-form.
    //            // The most common form of request-target.
    //            // https://tools.ietf.org/html/rfc7230#section-5.3.1
    //            OnOriginFormTarget(targetPath, target);
    //        }
    //        else if (ch == ByteAsterisk && target.Length == 1)
    //        {
    //            OnAsteriskFormTarget(method);
    //        }
    //        else if (startLine[targetStart..].GetKnownHttpScheme(out _))
    //        {
    //            OnAbsoluteFormTarget(targetPath, target);
    //        }
    //        else
    //        {
    //            // Assume anything else is considered authority form.
    //            // FYI: this should be an edge case. This should only happen when
    //            // a client mistakenly thinks this server is a proxy server.
    //            OnAuthorityFormTarget(method, target);
    //        }

    //        Method = method;
    //        if (method == HttpMethod.Custom)
    //        {
    //            _methodText = startLine[..versionAndMethod.MethodEnd].GetAsciiStringNonNullCharacters();
    //        }

    //        _httpVersion = versionAndMethod.Version;

    //        Debug.Assert(RawTarget != null, "RawTarget was not set");
    //        Debug.Assert(((IHttpRequestFeature)this).Method != null, "Method was not set");
    //        Debug.Assert(Path != null, "Path was not set");
    //        Debug.Assert(QueryString != null, "QueryString was not set");
    //        Debug.Assert(HttpVersion != null, "HttpVersion was not set");
    //    }

    //    // Compare with Http2Stream.TryValidatePseudoHeaders
    //    private void OnOriginFormTarget(TargetOffsetPathLength targetPath, Span<byte> target)
    //    {
    //        Debug.Assert(target[0] == ByteForwardSlash, "Should only be called when path starts with /");

    //        _requestTargetForm = HttpRequestTarget.OriginForm;

    //        if (target.Length == 1)
    //        {
    //            // If target.Length == 1 it can only be a forward slash (e.g. home page)
    //            // and we know RawTarget and Path are the same and QueryString is Empty
    //            RawTarget = ForwardSlash;
    //            Path = ForwardSlash;
    //            QueryString = string.Empty;
    //            // Clear parsedData as we won't check it if we come via this path again,
    //            // an setting to null is fast as it doesn't need to use a GC write barrier.
    //            _parsedRawTarget = _parsedPath = _parsedQueryString = null;
    //            _parsedAbsoluteRequestTarget = null;
    //            return;
    //        }

    //        // Read raw target before mutating memory.
    //        var previousValue = _parsedRawTarget;
    //        if (ServerOptions.DisableStringReuse ||
    //            previousValue == null || previousValue.Length != target.Length ||
    //            !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, target))
    //        {
    //            ParseTarget(targetPath, target);
    //        }
    //        else
    //        {
    //            // As RawTarget is the same we can reuse the previous parsed values.
    //            RawTarget = previousValue;
    //            Path = _parsedPath;
    //            QueryString = _parsedQueryString;
    //        }

    //        // Clear parsedData for absolute target as we won't check it if we come via this path again,
    //        // an setting to null is fast as it doesn't need to use a GC write barrier.
    //        _parsedAbsoluteRequestTarget = null;
    //    }

    //    private void ParseTarget(TargetOffsetPathLength targetPath, Span<byte> target)
    //    {
    //        // URIs are always encoded/escaped to ASCII https://tools.ietf.org/html/rfc3986#page-11
    //        // Multibyte Internationalized Resource Identifiers (IRIs) are first converted to utf8;
    //        // then encoded/escaped to ASCII  https://www.ietf.org/rfc/rfc3987.txt "Mapping of IRIs to URIs"

    //        try
    //        {
    //            // The previous string does not match what the bytes would convert to,
    //            // so we will need to generate a new string.
    //            RawTarget = _parsedRawTarget = target.GetAsciiStringNonNullCharacters();

    //            var queryLength = 0;
    //            if (target.Length == targetPath.Length)
    //            {
    //                // No query string
    //                if (ReferenceEquals(_parsedQueryString, string.Empty))
    //                {
    //                    QueryString = _parsedQueryString;
    //                }
    //                else
    //                {
    //                    QueryString = string.Empty;
    //                    _parsedQueryString = string.Empty;
    //                }
    //            }
    //            else
    //            {
    //                queryLength = ParseQuery(targetPath, target);
    //            }

    //            var pathLength = targetPath.Length;
    //            if (pathLength == 1)
    //            {
    //                // If path.Length == 1 it can only be a forward slash (e.g. home page)
    //                Path = _parsedPath = ForwardSlash;
    //            }
    //            else
    //            {
    //                var path = target[..pathLength];
    //                Path = _parsedPath = PathNormalizer.DecodePath(path, targetPath.IsEncoded, RawTarget, queryLength);
    //            }
    //        }
    //        catch (InvalidOperationException)
    //        {
    //            ThrowRequestTargetRejected(target);
    //        }
    //    }

    //    private int ParseQuery(TargetOffsetPathLength targetPath, Span<byte> target)
    //    {
    //        var previousValue = _parsedQueryString;
    //        var query = target[targetPath.Length..];
    //        var queryLength = query.Length;
    //        if (ServerOptions.DisableStringReuse ||
    //            previousValue == null || previousValue.Length != queryLength ||
    //            !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, query))
    //        {
    //            // The previous string does not match what the bytes would convert to,
    //            // so we will need to generate a new string.
    //            QueryString = _parsedQueryString = query.GetAsciiStringNonNullCharacters();
    //        }
    //        else
    //        {
    //            // Same as previous
    //            QueryString = _parsedQueryString;
    //        }

    //        return queryLength;
    //    }

    //    private void OnAuthorityFormTarget(HttpMethod method, Span<byte> target)
    //    {
    //        _requestTargetForm = HttpRequestTarget.AuthorityForm;

    //        // This is not complete validation. It is just a quick scan for invalid characters
    //        // but doesn't check that the target fully matches the URI spec.
    //        if (HttpCharacters.ContainsInvalidAuthorityChar(target))
    //        {
    //            ThrowRequestTargetRejected(target);
    //        }

    //        // The authority-form of request-target is only used for CONNECT
    //        // requests (https://tools.ietf.org/html/rfc7231#section-4.3.6).
    //        if (method != HttpMethod.Connect)
    //        {
    //            KestrelBadHttpRequestException.Throw(RequestRejectionReason.ConnectMethodRequired);
    //        }

    //        // When making a CONNECT request to establish a tunnel through one or
    //        // more proxies, a client MUST send only the target URI's authority
    //        // component (excluding any userinfo and its "@" delimiter) as the
    //        // request-target.For example,
    //        //
    //        //  CONNECT www.example.com:80 HTTP/1.1
    //        //
    //        // Allowed characters in the 'host + port' section of authority.
    //        // See https://tools.ietf.org/html/rfc3986#section-3.2

    //        var previousValue = _parsedRawTarget;
    //        if (ServerOptions.DisableStringReuse ||
    //            previousValue == null || previousValue.Length != target.Length ||
    //            !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, target))
    //        {
    //            // The previous string does not match what the bytes would convert to,
    //            // so we will need to generate a new string.
    //            RawTarget = _parsedRawTarget = target.GetAsciiStringNonNullCharacters();
    //        }
    //        else
    //        {
    //            // Reuse previous value
    //            RawTarget = _parsedRawTarget;
    //        }

    //        Path = string.Empty;
    //        QueryString = string.Empty;
    //        // Clear parsedData for path, queryString and absolute target as we won't check it if we come via this path again,
    //        // an setting to null is fast as it doesn't need to use a GC write barrier.
    //        _parsedPath = _parsedQueryString = null;
    //        _parsedAbsoluteRequestTarget = null;
    //    }

    //    private void OnAsteriskFormTarget(HttpMethod method)
    //    {
    //        _requestTargetForm = HttpRequestTarget.AsteriskForm;

    //        // The asterisk-form of request-target is only used for a server-wide
    //        // OPTIONS request (https://tools.ietf.org/html/rfc7231#section-4.3.7).
    //        if (method != HttpMethod.Options)
    //        {
    //            KestrelBadHttpRequestException.Throw(RequestRejectionReason.OptionsMethodRequired);
    //        }

    //        RawTarget = Asterisk;
    //        Path = string.Empty;
    //        QueryString = string.Empty;
    //        // Clear parsedData as we won't check it if we come via this path again,
    //        // an setting to null is fast as it doesn't need to use a GC write barrier.
    //        _parsedRawTarget = _parsedPath = _parsedQueryString = null;
    //        _parsedAbsoluteRequestTarget = null;
    //    }

    //    private void OnAbsoluteFormTarget(TargetOffsetPathLength targetPath, Span<byte> target)
    //    {
    //        Span<byte> query = target[targetPath.Length..];
    //        _requestTargetForm = HttpRequestTarget.AbsoluteForm;

    //        // absolute-form
    //        // https://tools.ietf.org/html/rfc7230#section-5.3.2

    //        // This code should be the edge-case.

    //        // From the spec:
    //        //    a server MUST accept the absolute-form in requests, even though
    //        //    HTTP/1.1 clients will only send them in requests to proxies.

    //        var disableStringReuse = ServerOptions.DisableStringReuse;
    //        var previousValue = _parsedRawTarget;
    //        if (disableStringReuse ||
    //            previousValue == null || previousValue.Length != target.Length ||
    //            !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, target))
    //        {
    //            // The previous string does not match what the bytes would convert to,
    //            // so we will need to generate a new string.
    //            RawTarget = _parsedRawTarget = target.GetAsciiStringNonNullCharacters();

    //            // Validation of absolute URIs is slow, but clients
    //            // should not be sending this form anyways, so perf optimization
    //            // not high priority

    //            if (!Uri.TryCreate(RawTarget, UriKind.Absolute, out var uri))
    //            {
    //                ThrowRequestTargetRejected(target);
    //            }

    //            _absoluteRequestTarget = _parsedAbsoluteRequestTarget = uri;
    //            Path = _parsedPath = uri.LocalPath;
    //            // don't use uri.Query because we need the unescaped version
    //            previousValue = _parsedQueryString;
    //            if (disableStringReuse ||
    //                previousValue == null || previousValue.Length != query.Length ||
    //                !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, query))
    //            {
    //                // The previous string does not match what the bytes would convert to,
    //                // so we will need to generate a new string.
    //                QueryString = _parsedQueryString = query.GetAsciiStringNonNullCharacters();
    //            }
    //            else
    //            {
    //                QueryString = _parsedQueryString;
    //            }
    //        }
    //        else
    //        {
    //            // As RawTarget is the same we can reuse the previous values.
    //            RawTarget = _parsedRawTarget;
    //            Path = _parsedPath;
    //            QueryString = _parsedQueryString;
    //            _absoluteRequestTarget = _parsedAbsoluteRequestTarget;
    //        }
    //    }

    //    internal void EnsureHostHeaderExists()
    //    {
    //        // https://tools.ietf.org/html/rfc7230#section-5.4
    //        // A server MUST respond with a 400 (Bad Request) status code to any
    //        // HTTP/1.1 request message that lacks a Host header field and to any
    //        // request message that contains more than one Host header field or a
    //        // Host header field with an invalid field-value.

    //        var hostCount = HttpRequestHeaders.HostCount;
    //        var hostText = HttpRequestHeaders.HeaderHost.ToString();
    //        if (hostCount <= 0)
    //        {
    //            if (_httpVersion == Http.HttpVersion.Http10)
    //            {
    //                return;
    //            }

    //            KestrelBadHttpRequestException.Throw(RequestRejectionReason.MissingHostHeader);
    //        }
    //        else if (hostCount > 1)
    //        {
    //            KestrelBadHttpRequestException.Throw(RequestRejectionReason.MultipleHostHeaders);
    //        }
    //        else if (_requestTargetForm != HttpRequestTarget.OriginForm)
    //        {
    //            // Tail call
    //            ValidateNonOriginHostHeader(hostText);
    //        }
    //        else if (!HttpUtilities.IsHostHeaderValid(hostText))
    //        {
    //            KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
    //        }
    //    }

    //    private void ValidateNonOriginHostHeader(string hostText)
    //    {
    //        if (_requestTargetForm == HttpRequestTarget.AuthorityForm)
    //        {
    //            if (hostText != RawTarget)
    //            {
    //                KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
    //            }
    //        }
    //        else if (_requestTargetForm == HttpRequestTarget.AbsoluteForm)
    //        {
    //            // If the target URI includes an authority component, then a
    //            // client MUST send a field - value for Host that is identical to that
    //            // authority component, excluding any userinfo subcomponent and its "@"
    //            // delimiter.

    //            // System.Uri doesn't not tell us if the port was in the original string or not.
    //            // When IsDefaultPort = true, we will allow Host: with or without the default port
    //            if (hostText != _absoluteRequestTarget.Authority)
    //            {
    //                if (!_absoluteRequestTarget.IsDefaultPort
    //                    || hostText != _absoluteRequestTarget.Authority + ":" + _absoluteRequestTarget.Port.ToString(CultureInfo.InvariantCulture))
    //                {
    //                    KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
    //                }
    //            }
    //        }

    //        if (!HttpUtilities.IsHostHeaderValid(hostText))
    //        {
    //            KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
    //        }
    //    }

    //    protected override void OnReset()
    //    {
    //        ResetHttp1Features();

    //        _requestTimedOut = false;
    //        _requestTargetForm = HttpRequestTarget.Unknown;
    //        _absoluteRequestTarget = null;
    //        _remainingRequestHeadersBytesAllowed = ServerOptions.Limits.MaxRequestHeadersTotalSize + 2;
    //        _requestCount++;

    //        MinResponseDataRate = ServerOptions.Limits.MinResponseDataRate;
    //    }

    //    protected override void OnRequestProcessingEnding()
    //    {
    //    }

    //    protected override string CreateRequestId()
    //        => StringUtilities.ConcatAsHexSuffix(ConnectionId, ':', _requestCount);

    //    protected override MessageBody CreateMessageBody()
    //        => Http1MessageBody.For(_httpVersion, HttpRequestHeaders, this);

    //    protected override void BeginRequestProcessing()
    //    {
    //        // Reset the features and timeout.
    //        Reset();
    //        TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutReason.KeepAlive);
    //    }

    //    protected override bool BeginRead(out ValueTask<ReadResult> awaitable)
    //    {
    //        awaitable = Input.ReadAsync();
    //        return true;
    //    }

    //    protected override bool TryParseRequest(ReadResult result, out bool endConnection)
    //    {
    //        var reader = new SequenceReader<byte>(result.Buffer);
    //        var isConsumed = false;
    //        try
    //        {
    //            isConsumed = ParseRequest(ref reader);
    //        }
    //        catch (InvalidOperationException)
    //        {
    //            if (_requestProcessingStatus == RequestProcessingStatus.ParsingHeaders)
    //            {
    //                KestrelBadHttpRequestException.Throw(RequestRejectionReason.MalformedRequestInvalidHeaders);
    //            }
    //            throw;
    //        }
    //        finally
    //        {
    //            Input.AdvanceTo(reader.Position, isConsumed ? reader.Position : result.Buffer.End);
    //        }

    //        if (result.IsCompleted)
    //        {
    //            switch (_requestProcessingStatus)
    //            {
    //                case RequestProcessingStatus.RequestPending:
    //                    endConnection = true;
    //                    return true;
    //                case RequestProcessingStatus.ParsingRequestLine:
    //                    KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidRequestLine);
    //                    break;
    //                case RequestProcessingStatus.ParsingHeaders:
    //                    KestrelBadHttpRequestException.Throw(RequestRejectionReason.MalformedRequestInvalidHeaders);
    //                    break;
    //            }
    //        }
    //        else if (!_keepAlive && _requestProcessingStatus == RequestProcessingStatus.RequestPending)
    //        {
    //            // Stop the request processing loop if the server is shutting down or there was a keep-alive timeout
    //            // and there is no ongoing request.
    //            endConnection = true;
    //            return true;
    //        }
    //        else if (RequestTimedOut)
    //        {
    //            // In this case, there is an ongoing request but the start line/header parsing has timed out, so send
    //            // a 408 response.
    //            KestrelBadHttpRequestException.Throw(RequestRejectionReason.RequestHeadersTimeout);
    //        }

    //        endConnection = false;
    //        if (_requestProcessingStatus == RequestProcessingStatus.AppStarted)
    //        {
    //            EnsureHostHeaderExists();
    //            return true;
    //        }
    //        else
    //        {
    //            return false;
    //        }
    //    }

    //    void IRequestProcessor.Tick(DateTimeOffset now) { }
    //}


}